﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Minestorm.Evolved.Scenes;
using Microsoft.Xna.Framework;
using Minestorm.Evolved.Animation;

namespace Minestorm.Evolved.SceneObjects
{
    public class Camera : SceneObject
    {
        public Matrix View { get; protected set; }
        public Matrix Projection { get; protected set; }

        public Vector3 LookAt { get; set; }
        public virtual Vector3 Position { get; set; }

        public override bool IsInViewFrustum(BoundingSphere sphere)
        {
            return true;
        }

        public override bool IsInViewFrustum(BoundingBox box)
        {
            return true;
        }
    }

    public class MapCamera : Camera
    {
        private Vector3Easing _easing;
        private Vector3 _zoomVector;
        private BoundingFrustum _viewFrustum;

        public override void LoadContent()
        {
            Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio, .2f, 10000f);

            _zoomVector = new Vector3(0, 0, 10);
            
            _viewFrustum = new BoundingFrustum(View * Projection);

            base.LoadContent();
        }

        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);

            if (_easing != null && _easing.State == EasingState.Started)
                LookAt = _easing.Value;

            View = Matrix.CreateLookAt(LookAt + _zoomVector, LookAt, Vector3.Up);

            _viewFrustum = new BoundingFrustum(View * Projection);
        }

        public override bool IsInViewFrustum(BoundingSphere sphere)
        {
            return _viewFrustum.Contains(sphere) != ContainmentType.Disjoint;
        }

        public override bool IsInViewFrustum(BoundingBox box)
        {
            return _viewFrustum.Contains(box) != ContainmentType.Disjoint;
        }

        public override Vector3 Position { get { return LookAt + _zoomVector; } set { } }

        private bool CheckEasing()
        {
            if (_easing == null)
            {
                _easing = new Vector3Easing();
                Scene.EasingManager.AddEasing(_easing);
            }

            if (_easing != null && _easing.State == EasingState.Started)
            {
                _easing.Stop();
                return true;
            }

            return false;
        }

        public Vector3 PanningTo { get; private set; }

        public void MoveTo(float x, float y, float z)
        {
            CheckEasing();
            LookAt = new Vector3(LookAt.X + x, LookAt.Y + y, LookAt.Z + z);
        }

        public void MoveTo(Vector3 target)
        {
            CheckEasing();
            LookAt = target;
        }

        public void PanTo(float x, float y, float z)
        {
            PanTo(new Vector3(x, y, z));
        }

        public void PanTo(Vector3 target)
        {
            var forceStop = CheckEasing();

            PanningTo = target;

            var func = forceStop ? new Easing.EasingType(EasingTypes.Regular.Out) : new Easing.EasingType(EasingTypes.Regular.InOut);

            _easing.Reset(LookAt, target, 1, func);
            _easing.Start();
        }
    }
}
